/**
 * 房间内的资源平衡策略
 */

/*
storageEmpty storage的东西

 */

let RES_BALANCE_ROOM = function () {
    let obj = {};
    // RESOURCES_ALL.forEach(e=>{
    //     obj[e] = 3000
    // })
    (["O","L","H","X","K","Z","U","GH2O"]).forEach(e=>{
        obj[e] = 3000
    })
    obj[RESOURCE_ENERGY] = 50000
    obj[RESOURCE_POWER] = 100
    return obj
}()

let RES_HOLD_ROOM = function () {
    // console.log(RESOURCES_ALL.length * 3000+ 50000);
    let obj = {};
    RESOURCES_ALL.forEach(e=>{
        obj[e] = 3000
    })
    return obj
}()

Creep.prototype.registerBalanceTerminalResource = function (){
    this.room.balancingTerminalResource = true
}


Creep.prototype.balanceTerminalResource = function (){
    let needBalance = pro.resRoomBalanceCache[this.room.name];
    let resTypes = _.keys(needBalance);
    while(resTypes.head()){
        let resType = resTypes.head()
        let resCnt = RES_BALANCE_ROOM[resType] || RES_HOLD_ROOM[resType];
        if((this.room.terminal.store[resType]||0)!=resCnt&&this.room.storage.store[resType]||
            (this.room.terminal.store[resType]||0)>resCnt)break;
        delete needBalance[resTypes.shift()]
    }
    if(this._balanceTerminalResource>5)return this.popTask();
    this._balanceTerminalResource = (this._balanceTerminalResource||0)+1;
    // HelperVisual.showText(this,resTypes.head())
    // this.say(pro.resRoomBalanceCache[this.room.name])
    let resType = resTypes.head();
    if(resType&&this.ticksToLive>30&&this.store.getResTypeList().length==0){
        let resCount = (RES_BALANCE_ROOM[resType]||RES_HOLD_ROOM[resType]) - (this.room.terminal.store[resType]||0)
        let ops = {
            resType: resType,
            resCount: resCount>0?resCount:-resCount
        }
        let fromTo  = [this.room.storage,this.room.terminal]
        if(resCount<0){
            fromTo  = [this.room.terminal,this.room.storage]
        }
        let task = [
            UtilsTask.task(fromTo[1],"fillRes",undefined,ops),
            UtilsTask.task(fromTo[0],"carryRes",undefined,ops)
        ]
        if(resTypes.length==1&&Math.abs(resCount)<=this.store.getFreeCapacity(resType)){
            this.popTask();
        }
        this.addTask(task)
        this.execLastTask();
    }else {
        this.popTask();
    }
}



Creep.prototype.roomStorageEmpty = function (){
    if(pro.checkEmptyStorage(this.room)||this.ticksToLive<30
        ||!this.room.find(FIND_FLAGS).filter(e=>e.getPrefix()=="storageEmpty").head()){
        this.popTask();
        this.execLastTask();
    }
    let res = this.room.storage.store.getLessResTypesExceptEnergy()
    let fromTo  = [this.room.storage,this.room.terminal]
    let resType = res.head();
    if(!resType)resType = RESOURCE_ENERGY
    let ops = {
        resType: resType,
        // resCount: this.room.storage.store[resType]
    }
    let task = [
        UtilsTask.task(fromTo[1],"fillRes",undefined,ops),
        UtilsTask.task(fromTo[0],"carryRes",undefined,ops)
    ]
    this.addTask(task);
    this.execLastTask();
}



let pro = {
    resRoomBalanceCache:{},
    update:function(room){
        //RES_HOLD_ROOM[resType]
        let needBalance = pro.resRoomBalanceCache[room.name]={}
        // _.keys(RES_BALANCE_ROOM).forEach(resType=>{
        //     if((room.storage.store[resType]||0)+(room.terminal.store[resType]||0)>=(RES_BALANCE_ROOM[resType]||0)&&
        //         room.terminal.store[resType]!=(RES_BALANCE_ROOM[resType]||0)){
        //         needBalance[resType]=1;//RES_BALANCE_ROOM[resType]-room.terminal.store[resType]
        //     }
        // })
        // _.keys(room.terminal.store).filter(e => (!RES_BALANCE_ROOM[e])&&room.terminal.store[e] > 0).forEach(resType=> needBalance[resType] = 1)

        RESOURCES_ALL.forEach(resType=>{
            let resCnt = RES_BALANCE_ROOM[resType] || RES_HOLD_ROOM[resType];
            if((room.terminal.store[resType]||0)!=resCnt&&room.storage.store[resType]||
                (room.terminal.store[resType]||0)>resCnt){
                needBalance[resType]=1;//RES_BALANCE_ROOM[resType]-room.terminal.store[resType]
            }
        })
    },

    roomRequire:{},//房间需求
    /**
     * 初始化房间需求
     * @param room
     */
    roomRequireInit:function (room) {
        pro.roomRequire[room.name] = {};
    },
    /**
     * 房间需求变化，如果为订单为0则删除
     * send cnt 的数量
     */
    roomRequireCal:function (room,resType,cnt) {
        if (!pro.roomRequire[room.name]) pro.roomRequire[room.name] = {}
        if (pro.roomRequire[room.name][resType] === undefined) pro.roomRequire[room.name][resType] = 0
        pro.roomRequire[room.name][resType] -= cnt
        if(pro.roomRequire[room.name][resType]==0)delete pro.roomRequire[room.name][resType]
    },
    /**
     * 房间需求数量
     * send cnt 的数量
     */
    roomRequireCnt:function (room,resType) {
        if (!pro.roomRequire[room.name]) return 0;
        if (pro.roomRequire[room.name][resType] === undefined) return 0;
        return pro.roomRequire[room.name][resType]
    },
    /**
     * 更新房间的需求
     * @param room
     */
    processRoom:function (room){
        pro.roomRequireInit(room);
        for(let resType of _.keys(RES_BALANCE_ROOM)){
            let targetStorageCnt = room.storage?(room.storage.store[resType]||0):0
            if(room.terminal.store[resType]+targetStorageCnt<RES_BALANCE_ROOM[resType]*2){
                pro.roomRequireCal(room,resType,-(RES_BALANCE_ROOM[resType]*2-(room.terminal.store[resType]+targetStorageCnt)));
                // pro.roomRequire[room.name] = {}
                // log(1111)
            }
        }
        // log(room.name,pro.roomRequire[room.name])
    },
    balanceWithOtherRoom:function(room){
        if((Game.time + room.hashCode()) % 12 != 0)return;
        pro.processRoom(room);
        /**
         * 平衡房间之间的资源的策略
         * 保证 storage + terminal >= RES_BALANCE_ROOM[resType]个以上
         * 当大于 RES_BALANCE_ROOM[resType] * 3 时供给
         * terminal 控制与 RES_BALANCE_ROOM[resType] 一致
         */
        if(!room.terminal.cooldown){
            // let t = Game.cpu.getUsed()
            let targetRooms = _.values(Game.rooms).filter(e=>e.my&&e.name!=room.name&&e.terminal)
                .map(e=>[e,Game.map.getRoomLinearDistance(e.name,room.name, true)])
                .sort((a,b)=>a[1]-b[1]).map(e=>e[0])

            let sendAble = {} // 计算哪些可以发送
            for(let resType of _.keys(RES_BALANCE_ROOM)){
                let StorageCnt = room.storage?room.storage.store[resType]:0
                if(room.terminal.store[resType]+StorageCnt>RES_BALANCE_ROOM[resType]*3
                    &&room.terminal.store[resType]==RES_BALANCE_ROOM[resType]){
                    sendAble[resType] = RES_BALANCE_ROOM[resType]
                }
            }
            for(let targetRoom of targetRooms){
                for(let resType in sendAble){
                    let requireCnt = pro.roomRequireCnt(targetRoom,resType)
                    if(requireCnt){
                        let amount = Math.min(requireCnt,sendAble[resType])
                        if(RESOURCE_ENERGY==resType)amount = Math.min(requireCnt,Math.floor(sendAble[resType]/2))
                        let code = room.terminal.send(resType,amount,targetRoom.name)
                        pro.resRoomBalanceCache[room.name][resType]=1;
                        pro.resRoomBalanceCache[targetRoom.name][resType]=1;
                        //log(room.name,targetRoom.name,amount,resType,code)
                        return;
                        //break;
                    }
                }
            }

        }
    },
    checkEmptyStorage(room){
        if(room.storage&&room.terminal){
            let resTypes = room.storage.store.getResTypeList()
            if (resTypes.filter(e => e != RESOURCE_ENERGY).head()) {
                return false;
            }
            if(room.storage.store[RESOURCE_ENERGY]>10000)return false;
        }
        return true;
    },
    storageEmpty:function (room) {
        if ((Game.time + room.hashCode()) % 3 != 0) return;
        if(!room.balancingTerminalResource&&!pro.checkEmptyStorage(room)){
            let carrier = room.creeps("carrier").filter(e => e.isFree()&&e.storeEmpty()&&e.ticksToLive>90).head();
            if(carrier) carrier.addTask([UtilsTask.task(room.storage,"roomStorageEmpty","registerBalanceTerminalResource")])
        }
    },
    sendEmptyClosestRoom:function (room){
        if(room.terminal&&!room.terminal.cooldown){
            let targetRoom = _.values(Game.rooms).filter(e=>e.my&&e.terminal&&e.name!=room.name)
                .map(e=>[e,Game.map.getRoomLinearDistance(room.name,e.name,true)])
                .sort((a,b)=>a[1]-b[1]).map(a=>a[0]).head() // 获得最近的可发送房间
            if(targetRoom){
                let res = room.terminal.store.getLessResTypesExceptEnergy()
                let resType = res.head();
                if(!resType)resType = RESOURCE_ENERGY
                let energyCnt = room.terminal.store[RESOURCE_ENERGY];
                if(!energyCnt)return;
                let amount = Math.min(energyCnt/2,room.terminal.store[resType])

                let code = room.terminal.send(resType,amount,targetRoom.name)
                // log(room.name,targetRoom.name,amount,resType,code)
            }
        }
    },
    exec:function (room){
        if ((Game.time + room.hashCode()) % 3 != 0) return;
        if(room.find(FIND_FLAGS).filter(e=>e.getPrefix()=="storageEmpty").head()){
            pro.storageEmpty(room)
            if(room.terminal&&room.terminal.store.getFreeCapacity(RESOURCE_ENERGY)<5000){
                pro.sendEmptyClosestRoom(room);
            }
        }
        else pro.balance(room);
    },
    balance:function (room) {
        if (!(room.storage && room.storage.my && room.terminal && room.terminal.my)) return;
        // 如果没更新过，或者30t跟新一次
        if (!pro.resRoomBalanceCache[room.name] || (Game.time + room.hashCode()) % 30 == 0) pro.update(room);

        if (!room.balancingTerminalResource&&_.keys(pro.resRoomBalanceCache[room.name]).length>0) {
            let carrier = room.creeps("carrier").filter(e => e.isFree()&&e.storeEmpty()&&e.ticksToLive>90).head();
            // if(carrier) carrier.say(_.keys(pro.resRoomBalanceCache[room.name]).length)
            if(carrier) carrier.addTask([UtilsTask.task(room.terminal,"balanceTerminalResource","registerBalanceTerminalResource")])
        }
        pro.balanceWithOtherRoom(room)
    }
}


global.StrategyResourceBalance=pro;